package com.zengjianjun.es.demo.highlevelclient.param;

import com.zengjianjun.es.demo.highlevelclient.options.ConditionOption;
import com.zengjianjun.es.demo.highlevelclient.options.TimeOption;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.HashMap;

/**
 * <p>es-查询参数包装类</p>
 * <hr/>
 * <p>使用前，先定义一个类，继承 EsQueryParam，并配合 {@link FieldValue} 以指定字段（包括字段名称、类型）。</p>
 * <p>应尽量遵循命名规范，自定义的类名，应与 elasticsearch 中的索引名称有关联。</p>
 *
 * <li>举例：在 elasticsearch 中你创建了一个索引，名为 abc，其中共有四个字段 filedA、filedB、filedC、filedD。</li>
 * <p>现在，你需要以这四个字段的其中任意n个为条件发起查询。其中：</p>
 * <p style="text-indent:32.4px;"> filedA 为 String 类型； </p>
 * <p style="text-indent:32.4px;"> filedB 为 Integer 类型。 </p>
 * <p style="text-indent:32.4px;"> filedC 为 Long 类型。 </p>
 * <p style="text-indent:32.4px;"> filedD 为 String 类型，但是你的条件值为 list，满足这个 list 中的所有文档都要返回。 </p>
 *
 * <p>那么，你可以定义这样一个类：</p>
 *
 * <p><blockquote><pre class="code">
 *          public class EsAbcQueryParam extends EsQueryParam {
 *              private static final long serialVersionUID = 1L;
 *              public EsAbcQueryParam aFiled(FieldValue&lt;String&gt; fieldValue) {
 *                  super.put("filedA", fieldValue);
 *                  return this;
 *              }
 *              public EsAbcQueryParam bFiled(FieldValue&lt;Integer&gt; fieldValue) {
 *                  super.put("filedB", fieldValue);
 *                  return this;
 *              }
 *              public EsAbcQueryParam cFiled(FieldValue&lt;Long&gt; fieldValue) {
 *                  super.put("filedC", fieldValue);
 *                  return this;
 *              }
 *              public EsAbcQueryParam dFiled(FieldValue&lt;List&lt;String&gt;&gt; fieldValue) {
 *                  super.put("filedD", fieldValue);
 *                  return this;
 *              }
 *          }
 * </pre></blockquote></p>
 *
 * <p>你可以在这个类上添加 @Getter 与 @NoArgsConstructor 作为在这个类中的 “别的属性” 的 <i>getter方法</i> 和 <i>无参构造方法</i>，如果你需要的话，可以用”lombok“ 或 “手写代码”的方式来实现。</p>
 *
 * <p>
 * <b>注意</b>:
 * 如果没有别的属性，请不要添加 “有参构造方法” 或 @AllArgsConstructor 注解，否则会运行失败。
 * </p>
 *
 * <p>现在，你已经定义好了这个类，使用方式如下：</p>
 *
 * <p><blockquote><pre class="code">
 *      EsGaidQuery.EsGaidQueryBuilder builder = EsGaidQuery.builder()
 *              .aField(FieldValue.<String>builder().value(aField).conditionOption(ConditionOption.equal).build())
 *              .bField(FieldValue.<Integer>builder().value(bField).conditionOption(ConditionOption.or).build())
 *              .cField(FieldValue.<Integer>builder().value(cField).conditionOption(ConditionOption.not_equal).build())
 *              .dField(FieldValue.<List<String>>builder().value(dField).conditionOption(ConditionOption.or).build())
 *              .timeOption(imeOption.builder()
 *                     .field("createTime")
 *                     .interval(0)
 *                     .startTime(startTime)
 *                     .endTime(endTime)
 *                     .build());
 * </pre></blockquote></p>
 *
 * <p>其中的 timeOption 你可以在 {@link TimeOption} 这个类中看到有关它的解释。</p>
 *
 * <p>得到 EsQueryParam 对象后，你可以用它来做一些查询工作了：</p>
 *
 * <p style="text-indent:32.4px;"> 例如：</p>
 * <p style="text-indent:64.8px;"> esSearch.queryList("abc", esQueryParam, from, size, Xyz.class); </p>
 *
 * <p style="text-indent:32.4px;"> from,size 用于限定查询的范围，类似于传统的分页方式。 </p>
 * <p style="text-indent:32.4px;"> Xyz.class 用来指定返回的 list 的类型。 </p>
 * <hr/>
 *
 * @author zengjianjun
 */
@Getter
@AllArgsConstructor
@NoArgsConstructor
public class EsQueryParam extends HashMap<String, FieldValue<?>> {

    private TimeOption timeOption;

    public EsQueryParam timeOption(TimeOption timeOption) {
        this.timeOption = timeOption;
        return this;
    }
}
